/*
 * Copyright 2012 Rivoli team
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.googlecode.rivoli.document.renderer.text

import com.googlecode.rivoli.RivoliException
import com.googlecode.rivoli.model.Element
import com.googlecode.rivoli.model.classhierarchy.ElementConverter
import com.googlecode.rivoli.model.classhierarchy.Utilities

import java.lang.reflect.ParameterizedType

abstract class AbstractTextRenderer<T> implements com.googlecode.rivoli.writer.text.TextRenderer {
	final List<String> render(Element element, int width) {
		T convertedElement = ElementConverter.convert(element, Utilities.getTypeArgument(findParameterizedType(getClass()), 0))

		render(convertedElement, width)
	}

	private ParameterizedType findParameterizedType(Class<?> currentType) {
		Class<?> superclass = currentType.superclass

		(superclass == AbstractTextRenderer) ? currentType.genericSuperclass : findParameterizedType(superclass)
	}

	protected abstract List<String> render(T convertedElement, int width) throws RivoliException

	protected List<String> renderChildren(T convertedElement, int width, boolean separateWithEmptyLine) {
		List<String> lines = []

		getElement(convertedElement).children.each {Element child ->
			if (separateWithEmptyLine && !lines.empty) {
				lines << ''
			}

			lines.addAll(getElementRenderer(child).render(child, width))
		}

		lines
	}

	protected Element getElement(Object convertedElement) {
		if (!convertedElement.hasProperty('element')) {
			throw new RivoliException("converted element of type '${convertedElement.class.name}' does not contain a reference to the original element")
		}

		convertedElement.element
	}

	protected com.googlecode.rivoli.writer.text.TextRenderer getRenderer(Object convertedElement) {
		getElementRenderer(getElement(convertedElement))
	}

	private static com.googlecode.rivoli.writer.text.TextRenderer getElementRenderer(Element element) {
		element.descriptor.getRenderer(com.googlecode.rivoli.writer.text.TextRenderer)
	}
}